package org.hcyspartnoc.luoxin.service.searchtopic.impl;

import cn.hutool.db.PageResult;
import jakarta.annotation.Resource;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.hcyspartnoc.luoxin.common.exception.common.CommonUtilsException;
import org.hcyspartnoc.luoxin.common.exception.searchtopic.QuestionException;
import org.hcyspartnoc.luoxin.mapper.searchtopic.QuestionMapper;
import org.hcyspartnoc.luoxin.pojo.dto.searchtopic.*;
import org.hcyspartnoc.luoxin.pojo.po.searchtopic.QuestionOptionPo;
import org.hcyspartnoc.luoxin.pojo.po.searchtopic.QuestionPo;
import org.hcyspartnoc.luoxin.pojo.vo.searchtopic.QuestionTypesVO;
import org.hcyspartnoc.luoxin.pojo.vo.searchtopic.QuestionVo;
import org.hcyspartnoc.luoxin.service.searchtopic.QuestionService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Service
public class QuestionServiceImpl implements QuestionService {
    @Resource
    private QuestionMapper questionMapper;
    @Override
    @Transactional
    public void insertQuestion(QuestionDto questionDto) throws QuestionException {
        // 获取题目类型列表
        List<QuestionTypesVO> questionTypes = questionMapper.getQuestionTypes();

        // 通过 queType 查找对应的 QuestionTypesVO
        Optional<QuestionTypesVO> matchedType = questionTypes.stream()
                .filter(typeVO -> typeVO.getId().equals(questionDto.getQueType()))
                .findFirst();
        // 如果没有找到匹配的类型，抛出异常
        if (matchedType.isEmpty()) {
            throw new QuestionException(QuestionException.QUESTION_TYPE_INVALID);
        }
        // 获取匹配的题目类型
        QuestionTypesVO questionType = matchedType.get();
        // 检查如果题目类型为选择题，确保 options 不为空
        if((Objects.equals(questionType.getQueType(), "单选题") ||
                Objects.equals(questionType.getQueType(), "多选题")) &&
                (questionDto.getOptions() == null || questionDto.getOptions().isEmpty())){
            throw new QuestionException(QuestionException.QUESTION_OPTIONS_INVALID);
        }
        QuestionPo questionPo=new QuestionPo();
        BeanUtils.copyProperties(questionDto,questionPo);
        questionMapper.insertQuestion(questionPo);
        if(Objects.equals(questionType.getQueType(), "单选题") ||
                Objects.equals(questionType.getQueType(), "多选题")){
            for (QuestionDto.QuestionOptions dtoOption : questionDto.getOptions()) {
                questionPo.addOption(dtoOption.getOption());
            }
            questionPo.setOptionsQueId(questionPo.getId());
            questionMapper.insertOptions(questionPo);
        }
    }

    @Override
    @Transactional
    public void updateQuestion(QuestionUpdateDto questionUpdateDto) throws QuestionException {
        QuestionPo questionPo = questionMapper.getQuestion(questionUpdateDto.getId());
        if(questionPo == null){
            throw new QuestionException(QuestionException.QUESTION_ERROR);
        }
        BeanUtils.copyProperties(questionUpdateDto,questionPo);
        questionPo.setOptionsByUpdateDto(questionUpdateDto);
        questionMapper.updateQuestion(questionPo);
        if(!questionUpdateDto.getOptions().isEmpty()){
            for (QuestionPo.QuestionOptions questionOptions : questionPo.getOptions()){
                questionMapper.updateQuestionOption(questionOptions);
            }
        }
    }

    @Override
    public List<QuestionVo> queryQuestion(QuestionSearchDto questionSearchDto) {
        return questionMapper.queryQuestion(questionSearchDto);
    }

    @Override
    public PageResult queryPageQuestion(QuestionPageDto questionPageDto) {
        //根据什么去查
        return null;
    }

    @Override
    public List<QuestionTypesVO> getQuestionTypes() {
        return questionMapper.getQuestionTypes();
    }

    @Override
    @Transactional
    public void insertQuestionsByExcel(QuestionFileDto questionFileDto) throws QuestionException {
        List<QuestionPo> questionPoList = new ArrayList<>();
        MultipartFile file = questionFileDto.getFile();
        try (InputStream inputStream = file.getInputStream()) {
            Workbook workbook = new XSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表
            // 遍历每一行
            for (Row row : sheet) {
                QuestionPo questionPo = new QuestionPo();
                questionPo.setBankId(questionFileDto.getBankId());
                for (int i = 0; i < row.getLastCellNum(); i++) {
                    Cell cell = row.getCell(i);

                    if (cell == null || cell.getCellType() == CellType.BLANK) {
                        continue;  // 跳过空单元格
                    }
                    switch (i) {
                        case 0 ->
                                questionPo.setQueTopic(cell.getStringCellValue());
                        case 1 ->
                                questionPo.setQueAnswer(cell.getStringCellValue());
                        case 2 ->
                                questionPo.setQueAnalysis(cell.getStringCellValue());
                        case 3, 4, 5, 6, 7 ->
                                questionPo.addOption(cell.getStringCellValue());
                        default -> throw new QuestionException(QuestionException.QUESTION_FORMAT_ERROR);
                    }
                }
                // 将questionVo对象保存到集合中
                questionPoList.add(questionPo);
            }
            questionMapper.insertQuestionsByExcel(questionPoList);
            // 将返回的主键ID赋值给对应的QuestionPo对象
            for (QuestionPo questionPo : questionPoList) {
                questionPo.setOptionsQueId(questionPo.getId());
                if (!questionPo.getOptions().isEmpty()) {
                    questionMapper.insertOptions(questionPo);
                }
            }
        } catch (IOException e) {
            throw new QuestionException(QuestionException.FILE_ERROR);
        }
    }

    @Override
    @Transactional
    public void insertQuestionsByWord(QuestionFileDto questionFileDto) throws QuestionException, CommonUtilsException {
        // 获取题目类型列表
        List<QuestionTypesVO> questionTypes = questionMapper.getQuestionTypes();
        List<QuestionPo> questionPoList = new ArrayList<>();
        MultipartFile file = questionFileDto.getFile();
        String textFileName = file.getOriginalFilename();
        if(textFileName == null){
            throw new CommonUtilsException(CommonUtilsException.SRC_NOT_EXISTS);
        }
        try {
            if (textFileName.endsWith(".doc")) { // 判断文件格式
                InputStream fis = file.getInputStream();
                WordExtractor wordExtractor = new WordExtractor(fis); // 使用HWPF组件中WordExtractor类从Word文档中提取文本或段落
                String allText = wordExtractor.getText(); // 获取文档的所有文本内容
                questionPoList = analysisWord(allText,questionTypes);
                fis.close();
            } else if (textFileName.endsWith(".docx")) {
                try {

                    InputStream fis = file.getInputStream();
                    // 使用Apache POI的XWPF组件处理docx文件
                    XWPFDocument docx = new XWPFDocument(fis);
                    if (docx.isEnforcedReadonlyProtection()) {
                        throw new IOException("不支持导入加密文档");
                    }
                    XWPFWordExtractor extractor = new XWPFWordExtractor(docx);
                    String allText = extractor.getText(); // 获取所有文本内容
                    questionPoList = analysisWord(allText,questionTypes);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 批量插入题目
            questionMapper.insertQuestionsByExcel(questionPoList);

            // 插入选项并设置关联的题目ID
            for (QuestionPo questionPo : questionPoList) {
                questionPo.setOptionsQueId(questionPo.getId());
                if (!questionPo.getOptions().isEmpty()) {
                    questionMapper.insertOptions(questionPo);
                }
            }
        } catch (IOException e) {
            throw new QuestionException(QuestionException.FILE_ERROR);
        }
    }

    @Override
    @Transactional
    public QuestionVo getQuestionDetails(Long questionId) throws QuestionException {
        QuestionPo questionPo = questionMapper.getQuestion(questionId);
        // 获取题目类型列表
        List<QuestionTypesVO> questionTypes = questionMapper.getQuestionTypes();
        // 通过 queType 查找对应的 QuestionTypesVO
        Optional<QuestionTypesVO> matchedType = questionTypes.stream()
                .filter(typeVO -> typeVO.getId().equals(questionPo.getQueType()))
                .findFirst();
        // 如果没有找到匹配的类型，抛出异常
        if (matchedType.isEmpty()) {
            throw new QuestionException(QuestionException.QUESTION_TYPE_INVALID);
        }
        QuestionVo questionVo = new QuestionVo();
        BeanUtils.copyProperties(questionPo,questionVo);
        // 获取匹配的题目类型
        QuestionTypesVO questionType = matchedType.get();
        if(Objects.equals(questionType.getQueType(), "单选题") ||
                Objects.equals(questionType.getQueType(), "多选题")){
                List<QuestionOptionPo> questionOptionPos = questionMapper.getQuestionOption(questionPo);
                questionVo.setOptionsFromPo(questionOptionPos);
            }
        return questionVo;
    }

    @Override
    public void deleteQuestion(Long questionId) throws QuestionException {
        int result = questionMapper.deleteQuestion(questionId);
        if(result == 0){
            throw new QuestionException(QuestionException.QUESTION_ERROR);
        }
        questionMapper.deleteQuestionOption(questionId);
    }

    private static List<QuestionPo> analysisWord(String allText, List<QuestionTypesVO> questionTypes) throws QuestionException {
        List<QuestionPo> questionPoList = new ArrayList<>();
        // 去掉无关文字，假设题型都是以“选择题”、“判断题”等字样开头
        allText = cleanIrrelevantText(allText);
        // 存储每种题型及其对应的题目
        Map<String, String> questionMap = new HashMap<>();
        // 根据题型名称对题目进行分类
        processQuestions(allText, questionMap);
        // 输出处理后的题目信息
        for (Map.Entry<String, String> entry : questionMap.entrySet()) {
            // 定义正则表达式，匹配题号（数字 + 点号）
            Pattern pattern = Pattern.compile("\\d+\\.");
            Matcher matcher = pattern.matcher(entry.getValue());

            List<Integer> indices = new ArrayList<>();
            // 找到所有题号的起始位置
            while (matcher.find()) {
                indices.add(matcher.start());
            }
            // 通过 queType 查找对应的 QuestionTypesVO
            // 遍历题目类型列表，与 entry.getKey() 的值进行比较
            String key = entry.getKey();
            Optional<QuestionTypesVO> matchedType = questionTypes.stream()
                    .filter(typeVO -> Objects.equals(typeVO.getQueType(), key)) // 假设 typeName 是 QuestionTypesVO 的字段
                    .findFirst();
            // 如果没有找到匹配的类型，抛出异常
            if (matchedType.isEmpty()) {
                throw new QuestionException(QuestionException.QUESTION_TYPE_INVALID);
            }
            // 获取匹配的题目类型
            QuestionTypesVO questionType = matchedType.get();
            // 分割文本，每个题号到下一个题号之间的内容就是一个题目
            for (int i = 0; i < indices.size(); i++) {
                QuestionPo questionPo = new QuestionPo();
                int startIndex = indices.get(i); // 当前题号的起始位置
                int endIndex = (i + 1 < indices.size()) ? indices.get(i + 1) : entry.getValue().length(); // 下一个题号的起始位置
                String question = entry.getValue().substring(startIndex, endIndex).trim();
                // 使用正则表达式提取选项和其他部分
                String[] optionMarkers = {"A.", "B.", "C.", "D.", "E."}; // 选项标志
                String answerMarker = "答案：";
                String analysisMarker = "解析：";

                // 提取题干：直到第一个选项之前的内容
                int firstOptionIndex = findFirstOptionIndex(question, optionMarkers);
                if (firstOptionIndex != -1) {
                    questionPo.setQueTopic(question.substring(0, firstOptionIndex).trim());// 题干内容
                } else {
                    questionPo.setQueTopic(question.trim());// 题干内容
                }

                // 提取选项：逐个提取 A. B. C. D. 等选项
                for (String marker : optionMarkers) {
                    int optionIndex = question.indexOf(marker, firstOptionIndex);
                    if (optionIndex != -1) {
                        int nextOptionIndex = findNextOptionIndex(question, optionIndex, optionMarkers);
                        questionPo.addOption(question.substring(optionIndex, nextOptionIndex).trim());
                    }
                }
                // 提取答案（括号内的内容）
                int leftBracketIndex = questionPo.getQueTopic().indexOf("（"); // 查找左括号
                int rightBracketIndex = questionPo.getQueTopic().indexOf("）", leftBracketIndex); // 查找右括号
                int leftParenthesisIndex = question.indexOf("("); // 查找英文左括号
                int rightParenthesisIndex = question.indexOf(")", leftParenthesisIndex); // 查找英文右括号
                if (leftBracketIndex != -1 && rightBracketIndex != -1) {
                    questionPo.setQueAnswer(questionPo.getQueTopic().substring(leftBracketIndex + 1, rightBracketIndex).trim()); // 提取括号内的内容
                    // 更新题干，去掉答案部分
                    questionPo.setQueTopic(questionPo.getQueTopic().substring(0, leftBracketIndex + 1).trim() + "  " + questionPo.getQueTopic().substring(rightBracketIndex).trim());
                } else if (leftParenthesisIndex != -1 && rightParenthesisIndex != -1) {
                    questionPo.setQueAnswer(questionPo.getQueTopic().substring(leftParenthesisIndex + 1, rightParenthesisIndex).trim());// 提取括号内的内容
                    // 更新题干，去掉答案部分
                    questionPo.setQueTopic(questionPo.getQueTopic().substring(0, leftParenthesisIndex + 1).trim() + "  " + questionPo.getQueTopic().substring(rightParenthesisIndex).trim());
                } else {
                    // 提取答案
                    int answerIndex = question.indexOf(answerMarker);
                    if (answerIndex != -1) {
                        int answerEndIndex = question.indexOf("\n", answerIndex);
                        if (answerEndIndex == -1) {
                            answerEndIndex = question.length(); // 如果答案是最后一部分
                        }
                        questionPo.setQueAnswer(question.substring(answerIndex + answerMarker.length(), answerEndIndex).trim());
                    }
                }
                // 提取解析
                int analysisIndex = question.indexOf(analysisMarker);
                if (analysisIndex != -1) {
                    int analysisEndIndex = question.indexOf("\n", analysisIndex);
                    if (analysisEndIndex == -1) {
                        analysisEndIndex = question.length(); // 如果解析是最后一部分
                    }
                    questionPo.setQueAnalysis(question.substring(analysisIndex + analysisMarker.length(), analysisEndIndex).trim());
                }
                if (Objects.equals(entry.getKey(), "单选题")) {
                    String string = entry.getValue();
                    questionPo.setQueType(1L);
                }
                questionPo.setQueType(questionType.getId());
                questionPoList.add(questionPo);
            }

        }
        return questionPoList;
    }
    // 去掉无关的文本，比如大标题、章节名称等
    private static String cleanIrrelevantText(String text) {
        // 假设无关文字位于文档开头的某个部分，并通过标识符移除（例如“题库”、“章节”之类的关键字）
        String[] irrelevantKeywords = {"题库", "章节", "目录"};
        for (String keyword : irrelevantKeywords) {
            text = text.replaceAll("(?i)" + keyword + ".*", ""); // 使用正则忽略大小写并移除所有无关部分
        }
        return text;
    }
    // 辅助方法：找到第一个选项的位置
    private static int findFirstOptionIndex(String question, String[] optionMarkers) {
        int firstOptionIndex = -1;
        for (String marker : optionMarkers) {
            int index = question.indexOf(marker);
            if (index != -1 && (firstOptionIndex == -1 || index < firstOptionIndex)) {
                firstOptionIndex = index;
            }
        }
        if(firstOptionIndex != -1){
            return firstOptionIndex;
        }
        String answerMarker = "答案：";
        String analysisMarker = "解析：";
        firstOptionIndex = question.indexOf(answerMarker);
        if(firstOptionIndex != -1){
            return firstOptionIndex;
        }
        firstOptionIndex = question.indexOf(analysisMarker);
        return firstOptionIndex;
    }

    // 辅助方法：找到下一个选项的位置
    private static int findNextOptionIndex(String question, int currentOptionIndex, String[] optionMarkers) {
        int nextOptionIndex = question.length(); // 默认下一个选项是题目末尾
        int answerIndex = question.indexOf("答案："); // 找到答案的起始位置
        int analysisIndex = question.indexOf("解析："); // 找到答案的起始位置
        // 如果找到了答案，设置下一个选项的结束位置为答案的起始位置
        if (answerIndex != -1) {
            nextOptionIndex = answerIndex; // 将下一个选项的结束位置设置为答案的起始位置
        }
        // 如果找到了解析，且解析的位置早于答案，则更新下一个选项的结束位置
        if (analysisIndex != -1 && (answerIndex == -1 || analysisIndex < answerIndex)) {
            nextOptionIndex = analysisIndex; // 将下一个选项的结束位置设置为解析的起始位置
        }
        for (String marker : optionMarkers) {
            int index = question.indexOf(marker, currentOptionIndex + 1);
            if (index != -1 && index < nextOptionIndex) {
                nextOptionIndex = index;
            }
        }
        return nextOptionIndex;
    }
    // 处理题目，按题型进行分类
    private static void processQuestions(String allText, Map<String, String> questionMap) {
        String[] lines = allText.split("\n"); // 按行拆分文本
        String currentType = ""; // 当前的题型
        StringBuilder currentQuestions = new StringBuilder();

        for (String line : lines) {
            line = line.trim();
            if (line.matches("^[一二三四五六七八九十\\\\d]{0,3}[、.\\\\s]*?(单选题|多选题|判断题|填空题|问答题).*")) { // 判断是否为题型的标志
                // 如果发现新的题型，保存之前的题目
                if (!currentType.isEmpty() && currentQuestions.length() > 0) {
                    questionMap.put(currentType, currentQuestions.toString());
                }
                // 更新当前的题型
                // 更新当前的题型，去掉前面的序号
                currentType = line.replaceAll("^[一二三四五六七八九十\\\\d]{0,3}+[、.\\\\s]*", "");
                currentQuestions.setLength(0); // 清空当前题目
            } else if (line.matches("^\\d+.*")) { // 题目必须有连续题号
                currentQuestions.append(line).append("\n");
            }else{
                currentQuestions.append(line).append("\n");
            }
        }
        // 最后处理一组题目
        if (!currentType.isEmpty() && currentQuestions.length() > 0) {
            questionMap.put(currentType, currentQuestions.toString());
        }
    }
}
